package pa2.system;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.Map;
import java.util.concurrent.ScheduledThreadPoolExecutor;

import pa2.node.LocalNodeFactory;
import pa2.node.NetworkNodeFactory;
import pa2.node.Node;
import pa2.node.NodeData;
import pa2.node.NodeFactory;
import pa2.node.SimpleNodeFactory;
import pa2.node.StatisticNodeFactory;
import pa2.util.EqualityCompare;
import pa2.util.Job;
import pa2.util.PeerNameEvent;



public class PeerImpl extends UnicastRemoteObject implements Peer, Runnable {

	/**
	 * 
	 */
	private static final long serialVersionUID = -3988350803289314017L;
	private ScheduledThreadPoolExecutor threadPool;
	private String name;
	private NodeFactory nodeFactory;

	public PeerImpl(String name, int threadCount) throws RemoteException {
		super();
		this.name = name;
		this.threadPool = new ScheduledThreadPoolExecutor(threadCount);
		this.createFactory();
	}
	
	//TODO implement changes to factories here
	private void createFactory() {
		this.nodeFactory = new NetworkNodeFactory(
								new StatisticNodeFactory(
										new LocalNodeFactory(
												new SimpleNodeFactory(),
												this), 
										new PeerNameEvent(this.name)),
								null);
	}
	

	@Override
	public <K extends EqualityCompare<K>, V, M extends Map<K,V>>
		Node<K,V,M> createNode(K key, NodeData<K,V,M> data) throws RemoteException{
		//TODO add node to local vector?
//		System.out.println(
//				"Peer["+name+"]: Node<"+key+
//				"> CREATED on "+Thread.currentThread().getName());
		return this.nodeFactory.createNode(key, data);
	}

	@Override
    public <K extends EqualityCompare<K>, V, M extends Map<K,V>>
		void destroyNode(Node<K,V,M> node)throws RemoteException {
		//TODO remove node from local vector?
		System.out.println(
				"Peer["+name+"]: Node<"+node.getKey()+
				"> DELETED on "+Thread.currentThread().getName());
		this.nodeFactory.destroyNode(node);
	}


	public synchronized void queue(Job runnable) {
		threadPool.submit(runnable);
	}
	
	
	@Override
	public String getName() throws RemoteException {
		return this.name;
	}


	@Override
	public void run() {
		String host = "localhost";
		String port = Integer.toString(Registry.REGISTRY_PORT);

		try {
			Registry registry = LocateRegistry.getRegistry(host, Registry.REGISTRY_PORT);
			SystemManager sysMgr = (SystemManager) registry.lookup("rmi://" + host + ":" + port + "/" + SystemManager.SERVICENAME);            

			sysMgr.registerPeer(this);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}
